package com.samsungmobile.common_module;

import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;

import com.ipx.www.api.services.smsapi51.types.SendResponse;
import com.samsungmobile.common.ConfOta;
import com.samsungmobile.common.Logger;
import com.samsungmobile.common.channel.ServletManager;
import com.samsungmobile.common.db.value.IntValue;
import com.samsungmobile.common.db.value.StringValue;
import com.samsungmobile.common.util.EasyString;
import com.samsungmobile.common_module.Exception.CommonModuleException;
import com.samsungmobile.common_module.SMS.RequestBean;
import com.samsungmobile.common_module.SMS.Service.IPX;
import com.samsungmobile.common_module.SMS.Service.Materna;
import com.samsungmobile.common_module.SMS.Service.OtaService;
import com.samsungmobile.security.UKDESEncryptDecrypt;

public class SendMTM extends ServletManager {

	// Parameter Values
	private String spDest_address = "";
	private String spMessage_type = "";
	private String spMessage = "";
	private String spOperator = "";
	private String spUrl = "";
	private String spSource_Address = "";
	private String spSec_Key = "";
	private String spUserNo = "";
	private String spGateway = "";
	/**
	 * Reference id
	 * IPX: Referenced order of the premium message (normally a message_id from a MO)
	 */
	private String spReference_id = "";

	private String sCountry = "";
	
//	Required data is missing:
	private final String[] safSUCCESS = {"0","SUCCESS"};
	
	private final String[] safEMPTY_MESSAGE = {"102", "EMPTY_MESSAGE"};
	private final String[] safEMTPY_OPERATOR = {"103", "EMTPY_OPERATOR"};
	private final String[] safEMPTY_URL = {"104", "EMPTY_URL"};

//	Invalid input data:
	private final String[] safINVALID_DESTINATION_ADDRESS = {"200", "INVALID_DESTINATION_ADDRESS"};
	private final String[] safINVALID_MESSAGE_TYPE = {"201", "INVALID_MESSAGE_TYPE"};
	private final String[] safINVALID_OPERATOR = {"203", "INVALID_OPERATOR"};
	private final String[] safINVALID_SOURCE_ADDRESS = {"205", "INVALID_SOURCE_ADDRESS"};
	/**
	 * INVALID_REFERENCE_ID	
	 * The reference id was invalid. (unused)
	 */
	private final String[] safINVALID_REFERENCE_ID = {"206", "INVALID_REFERENCE_ID"};
	
	private final String[] safINVALID_USER_NO = {"207", "INVALID_USER_NO"};
	
//	Max data size exceeded:	
	private final String[] safEXCEEDED_MESSAGE_LENTGTH = {"302", "EXCEEDED_MESSAGE_LENTGTH"};
	private final String[] safEXCEEDED_URL_LENGTH = {"304", "EXCEEDED_URL"};
	private final String[] safEXCEEDED_REFERNCE_ID_LENTGTH = {"306", "EXCEEDED_REFERNCE_ID_LENTGTH"};
	
//	Technical problems with service provider:
	private String sfSERVICE_ERROR = "400";
		
//	Technical problems with the API:
	private final String[] safAPI_INTERNAL_ERROR = {"500", "API_INTERNAL_ERROR"};
	private final String[] safAPI_AUTHORIZATION_ERROR = {"501", "API_AUTHORIZATION_ERROR"};
	private final String[] safAPI_TIMEOUT = {"502", "API_TIMEOUT"};
	private final String[] safAPI_UNKNOWN_OTA_SERVICE = {"503", "UNKNOWN_OTA_SERVICE"};
	
	private final int ifMAX_MESSAGE_LENGTH = 140;
	private final int ifMAX_URL_LEHGTH = 140;
	private final int ifMAX_REFERENCE_ID_LEHGTH = 150;

	/* (non-Javadoc)
	 * @see com.samsungmobile.common.channel.ServletManager#process()
	 */
	protected void process() throws Exception {

		HashMap<String,String> hm = new HashMap<String,String>();
		PrintWriter out = res.getWriter();

		try {
			res.setContentType("text/xml; charset=UTF-8");
			
			setParams(req);
			checkValidation();
			SendResponse[] soapResponse = sendSMS();

			String sResponseId = getResponseId();
			hm.put("RESPONSE_ID", sResponseId );
			hm.put("MESSAGE_ID", getMessageId(soapResponse));
			hm.put("RESULT_CODE", safSUCCESS[0]);
			hm.put("RESULT_MESSAGE", safSUCCESS[1]);
			
			writeLog(hm, sResponseId, soapResponse);
		} catch (CommonModuleException e) {
			Logger.LOG_NOHUP.error(e);
			hm.put("RESPONSE_ID", "");
			hm.put("MESSAGE_ID", "");
			hm.put("RESULT_CODE", e.getMessages()[0]);
			hm.put("RESULT_MESSAGE", e.getMessages()[1]);
		
		} catch (Exception e) {
			Logger.LOG_NOHUP.error(e);
			hm.put("RESULT_CODE", safAPI_INTERNAL_ERROR[0]);
			hm.put("RESULT_MESSAGE", safAPI_INTERNAL_ERROR[1]);
			e.printStackTrace();
		
		} finally {
			responseReturnXml(out, hm);
			
		}
	}
	
	/**
	 * @param soapResponse
	 * @return
	 */
	private String getMessageId(SendResponse[] soapResponse){
		
		String sMessageId = "";
		
		Logger.LOG_NOHUP.debug("soapResponse.length="+soapResponse.length);
		for (int i=0; i < soapResponse.length; i++) {
			try {
				if ( i==0) {
					sMessageId += soapResponse[i].getMessageId();
				}
				else {
					sMessageId += "," + soapResponse[i].getMessageId();
				}
			} catch(Exception e) {
				Logger.LOG_NOHUP.error(e);
				return "0";
			}
		}
		
		return sMessageId;
	}
	
	/**
	 * @return
	 * @throws CommonModuleException
	 */
	private String getResponseId() throws CommonModuleException{
		
		StringBuffer sbQuery = new StringBuffer();
		sbQuery.append("select G_MTM_SEND_LOG_SEQ.nextval as seq from dual");			

		String sReturn = singleValueQuery(sbQuery.toString());
		
		if (sReturn.equals("")) 
			throw new CommonModuleException(safAPI_INTERNAL_ERROR);
		
		return sReturn;
	}

	/**
	 * @param out
	 * @param hmResult
	 */
	private void responseReturnXml ( PrintWriter out, HashMap<String,String> hmResult ){

		StringBuffer sbRes = new StringBuffer();
		
		sbRes.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
		sbRes.append("<result>\n");
		sbRes.append("	<responseId>").append(hmResult.get("RESPONSE_ID")).append("</responseId>\n");
		sbRes.append("	<messageId>").append(hmResult.get("MESSAGE_ID")).append("</messageId>\n");
		sbRes.append("	<responseCode>").append(hmResult.get("RESULT_CODE")).append("</responseCode>\n");
		sbRes.append("	<responseMessage>").append(hmResult.get("RESULT_MESSAGE")).append("</responseMessage>\n");
		sbRes.append("</result>\n");
		
		out.println(sbRes);
	}
	
	/**
	 * @param request
	 */
	private void setParams(HttpServletRequest request) throws Exception {
		
		spDest_address 				= EasyString.toString(request.getParameter("dest_address")).trim();
		spMessage_type 				= EasyString.toString(request.getParameter("message_type")).trim();
		spMessage 					= EasyString.toString(request.getParameter("message"),"text").trim();
		spOperator 					= EasyString.toString(request.getParameter("operator")).trim();
		spOperator					= spOperator.toLowerCase();
		
		spUrl				 		= EasyString.toString(request.getParameter("url")).trim();
		spSource_Address 			= EasyString.toString(request.getParameter("source_address"),"Samsung").trim();
		spSec_Key		 			= EasyString.toString(request.getParameter("sec_key")).trim();
		spReference_id 				= EasyString.toString(request.getParameter("reference_id")).trim();
		spUserNo	 				= EasyString.toString(request.getParameter("user_no")).trim();
		
		sCountry = getCountry();
		//Define what SMS GateWay (IPX, Materna... ) will be used.
		spGateway	 				= EasyString.toString(request.getParameter("gateway"), ConfOta.getConf(sCountry + ".otaService")).trim();
		spGateway					= spGateway.toLowerCase();
		
		UKDESEncryptDecrypt ukdes = new UKDESEncryptDecrypt();
		spSec_Key = ukdes.decrypt(spSec_Key);
		
		//remove protocol type "http://" in case there are prefix like "http://" or "https://"
		if( spUrl.startsWith("http") ){
			spUrl = spUrl.substring(spUrl.indexOf("//")+2);
		}
	}

	/**
	 * @param hm
	 * @param sResponseId
	 * @param soapResponse
	 * @throws CommonModuleException
	 */
	private void writeLog(HashMap<String,String> hm, String sResponseId, SendResponse[] soapResponse) throws CommonModuleException{

		StringBuffer sbQuery = new StringBuffer();
		
		sbQuery.append("insert into G_MTM_SEND_LOG\n");			
		sbQuery.append("( seq_id, user_no, da, message_type, segnum, country_code )\n"); 
		sbQuery.append("values( ?, ?, ?, ?, ?, ?)");
		
		Vector<Object> vParam = new Vector<Object>();
		vParam.add(new StringValue(sResponseId));   
		vParam.add(new StringValue(spUserNo));		// optional value
        vParam.add(new StringValue(spDest_address));    
        vParam.add(new StringValue(spMessage_type));
        
        int iSuccessSegmentCnt = 0;

        for (int i=0; i < soapResponse.length; i++){
        	if (soapResponse[i].getResponseCode() == 0){
        		iSuccessSegmentCnt++;
        	}else{
        		hm.put("RESULT_CODE", sfSERVICE_ERROR);
    			hm.put("RESULT_MESSAGE", soapResponse[i].getResponseCode()
    					+":"+soapResponse[i].getResponseMessage()
    					+":"+soapResponse[i].getReasonCode());
        	}
        }
        
        vParam.add(new IntValue(iSuccessSegmentCnt));
        
		String sCountryCode = ConfOta.getConf(sCountry + ".code");
			
        vParam.add(new StringValue(sCountryCode));  
        //vParam.add(new StringValue(spReference_id));
        
        if(iSuccessSegmentCnt != 0)
			if(!updateQuery(sbQuery.toString(), vParam))
				throw new CommonModuleException(safAPI_INTERNAL_ERROR);
	}

	/**
	 * @return
	 * @throws Exception
	 */
	private SendResponse[] sendSMS() throws Exception  {

		SendResponse[] response = null;
		OtaService otaService = null;
		
		RequestBean rb = new RequestBean();
		
		rb.setMsisdn(spDest_address);
		rb.setOriginatingAddress(spSource_Address);
		rb.setSmsType(spMessage_type);
		
		if (spMessage_type.equals("text")) {
			rb.setMessage(spMessage);

		} else if (spMessage_type.equals("wapsetting") || spMessage_type.equals("mmssetting")) {
			rb.setOperator(spOperator);
			
		} else if (spMessage_type.equals("wappush")) {
			rb.setOperator(spOperator);
			rb.setMessage(spMessage);
			rb.setUrl(spUrl);
		}

		// set reference id
		rb.setReferenceId(spReference_id);
		
		if(spGateway.equals("ipx")) {
			otaService = new IPX();
			
		}else if( spGateway.equals("materna") ) {
			otaService = new Materna();

		}
		
		response = otaService.sendMessage(rb);
		
		return response;
	
	}

	/**
	 * @throws CommonModuleException
	 */
	private void checkValidation() throws CommonModuleException {

		String[] saCountry = ConfOta.getArray("countries");
		String sCountries = StringUtils.join(saCountry,"|");
		
		Calendar paramDate = Calendar.getInstance(Locale.GERMANY);
		Calendar rightNow = Calendar.getInstance(Locale.GERMANY);
		
		if (spSec_Key.equals(""))
			throw new CommonModuleException(safAPI_AUTHORIZATION_ERROR);
		
		String sYear = spSec_Key.substring(0, 4);
		String sMonth = spSec_Key.substring(4, 6);
		
		String sDest_address = spSec_Key.substring(6);
		
		paramDate.set( Integer.parseInt(sYear)
				,Integer.parseInt(sMonth)-1
				,1
				);		
		
		SimpleDateFormat formatter = new SimpleDateFormat("yyyyMM");
		
        String sRightNow = formatter.format(rightNow.getTime());
        String sParamDate = formatter.format(paramDate.getTime());
        
		if (!spDest_address.matches("^("+sCountries+")\\d{9,11}")) {
			throw new CommonModuleException(safINVALID_DESTINATION_ADDRESS);
			
		} else if( !sRightNow.equals(sParamDate) ){
			throw new CommonModuleException(safAPI_AUTHORIZATION_ERROR);
			
		} else if( !sDest_address.equals(spDest_address) ){
			throw new CommonModuleException(safAPI_AUTHORIZATION_ERROR);
		
		} else if (!spMessage_type.matches("^(text|wapsetting|mmssetting|wappush)$") ) {
			throw new CommonModuleException(safINVALID_MESSAGE_TYPE);

		} else if ( !spSource_Address.matches("(\\d{1,16}|\\w{1,11})")){
			throw new CommonModuleException(safINVALID_SOURCE_ADDRESS);
		}
		
		if ( spMessage_type.equals("text")){
			checkValidation4Text();
			
		}else if ( spMessage_type.equals("wapsetting") || spMessage_type.equals("mmssetting") ){
			checkValidation4WapMmsSetting();
			
		}else if ( spMessage_type.equals("wappush")){
			checkValidation4WapPush();
			
		}
		
		// validate reference id if exists (2010-06-17 Andreas Happ)
		if( !spReference_id.equals("") && spReference_id.length() > ifMAX_REFERENCE_ID_LEHGTH) {
			throw new CommonModuleException(safEXCEEDED_REFERNCE_ID_LENTGTH);
		}
		
		// validate user_no
		if( !spUserNo.equals("") && !spUserNo.matches("\\d{0,20}")){
			throw new CommonModuleException(safINVALID_USER_NO);
		}
		
		// unknown ota service error
		if (!spGateway.matches("^(ipx|materna)$") ) {
			throw new CommonModuleException(safAPI_UNKNOWN_OTA_SERVICE);
		}		
	}
	
	/**
	 * @throws CommonModuleException
	 */
	private void checkValidation4Text()	throws CommonModuleException {
		
		if (spMessage.length() == 0 ) {
			throw new CommonModuleException(safEMPTY_MESSAGE);
	
		}else if( spMessage.length() > ifMAX_MESSAGE_LENGTH ){
			throw new CommonModuleException(safEXCEEDED_MESSAGE_LENTGTH);
			
		}
	}

	/**
	 * @throws CommonModuleException
	 */
	private void checkValidation4WapMmsSetting() throws CommonModuleException {
				
		validateOperator();

	}
	
	private void checkValidation4WapPush() throws CommonModuleException {
		
		if (spMessage.length() == 0 ) {
			throw new CommonModuleException(safEMPTY_MESSAGE);
	
		}else if( spMessage.length() > ifMAX_MESSAGE_LENGTH ){
			throw new CommonModuleException(safEXCEEDED_MESSAGE_LENTGTH);
			
		}else if( spUrl.length() == 0 ) {
			throw new CommonModuleException(safEMPTY_URL);
			
		}else if( spUrl.length() > ifMAX_URL_LEHGTH ) {
			throw new CommonModuleException(safEXCEEDED_URL_LENGTH);
			
		}

		validateOperator();
	}

	/**
	 * @throws CommonModuleException
	 */
	private void validateOperator() throws CommonModuleException{

//		sfEMTPY_OPERATOR
		if (spOperator.length() == 0 ) {
			throw new CommonModuleException(safEMTPY_OPERATOR);
			
		}
		
		boolean bRtn = false ;
		if( !sCountry.equals("") ) {
			String[] saOperator = ConfOta.getArray(sCountry + ".operators");
			for( int i=0; i < saOperator.length; i++){
				if ( saOperator[i].equals(spOperator) ){
					bRtn = true;
					break;
				}
			}
		}
		
		if (!bRtn){
			throw new CommonModuleException(safINVALID_OPERATOR);
			
		}
	}
	
	/**
	 * @return
	 * @throws CommonModuleException
	 */
	private String getCountry() throws CommonModuleException{

		String[] saCountry = ConfOta.getArray("countries");
		String sCountry = "";
		
		for ( int i=0; i < saCountry.length; i++){
			
			if( spDest_address.startsWith(saCountry[i]) ){
				sCountry = saCountry[i];
				break;
			}
		}
		
		return sCountry;
	}
}